package stef.home.arp.labos2;

import java.awt.EventQueue;

import javax.naming.ldap.Rdn;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import javax.swing.JRadioButton;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.awt.Label;

import javax.swing.ButtonGroup;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import javax.swing.SwingConstants;

public class Simplex {

	private JFrame frmSimplex;
	private final ButtonGroup buttonGroup = new ButtonGroup();
	private JTextField txtA;
	private JTextField txtB;
	private JTextField txtC;
	private JTextField txtE;
	private JTextField txtX;
	private JTextField txtT;
	private double[][] x;
	private double[] p;
	private int f;
	private int n;
	private JRadioButton rdbtnF1;
	private JRadioButton rdbtnF2;
	private JRadioButton rdbtnF3;
	private JRadioButton rdbtnF4;
	private JLabel lblXsol = new JLabel();
	private JTextField txtPath;
	private boolean error = false;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					Simplex window = new Simplex();
					window.frmSimplex.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the application.
	 */
	public Simplex() {
		initialize();
	}

	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize() {
		frmSimplex = new JFrame();
		frmSimplex.setTitle("Simplex");
		frmSimplex.setBounds(100, 100, 664, 382);
		frmSimplex.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		JPanel panel = new JPanel();
		frmSimplex.getContentPane().add(panel, BorderLayout.WEST);
		GridBagLayout gbl_panel = new GridBagLayout();
		gbl_panel.columnWidths = new int[]{0, 0};
		gbl_panel.rowHeights = new int[]{0, 0, 0, 0, 0};
		gbl_panel.columnWeights = new double[]{1.0, Double.MIN_VALUE};
		gbl_panel.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0};
		panel.setLayout(gbl_panel);
		
		rdbtnF1 = new JRadioButton("f1(x,y) = 10*(x^2-y)^2+(1-x)^2");
		rdbtnF1.setSelected(true);
		GridBagConstraints gbc_rdbtnF1 = new GridBagConstraints();
		gbc_rdbtnF1.anchor = GridBagConstraints.WEST;
		gbc_rdbtnF1.insets = new Insets(0, 0, 5, 0);
		gbc_rdbtnF1.gridx = 0;
		gbc_rdbtnF1.gridy = 0;
		panel.add(rdbtnF1, gbc_rdbtnF1);
		
		rdbtnF2 = new JRadioButton("f2(x,y) = (x-4)^2 + 4(y-2)^2");
		GridBagConstraints gbc_rdbtnF2 = new GridBagConstraints();
		gbc_rdbtnF2.anchor = GridBagConstraints.WEST;
		gbc_rdbtnF2.insets = new Insets(0, 0, 5, 0);
		gbc_rdbtnF2.gridx = 0;
		gbc_rdbtnF2.gridy = 1;
		panel.add(rdbtnF2, gbc_rdbtnF2);
		
		rdbtnF3 = new JRadioButton("f3(x1,x2,x3,x4,x5) = (x1-p1)^2 + (x2-p2)^2 + ... + (x5-p5)^2");
		GridBagConstraints gbc_rdbtnF3 = new GridBagConstraints();
		gbc_rdbtnF3.anchor = GridBagConstraints.WEST;
		gbc_rdbtnF3.insets = new Insets(0, 0, 5, 0);
		gbc_rdbtnF3.gridx = 0;
		gbc_rdbtnF3.gridy = 2;
		panel.add(rdbtnF3, gbc_rdbtnF3);
		
		JPanel panel_11 = new JPanel();
		GridBagConstraints gbc_panel_11 = new GridBagConstraints();
		gbc_panel_11.insets = new Insets(0, 0, 5, 0);
		gbc_panel_11.fill = GridBagConstraints.BOTH;
		gbc_panel_11.gridx = 0;
		gbc_panel_11.gridy = 3;
		panel.add(panel_11, gbc_panel_11);
		
		JLabel lblPathf = new JLabel("Path (P) :");
		panel_11.add(lblPathf);
		
		txtPath = new JTextField();
		txtPath.setText("D:\\Fer\\workspace\\APR\\p.txt");
		panel_11.add(txtPath);
		txtPath.setColumns(20);
		
		JButton btnBrowse = new JButton("Browse");
		final JFileChooser fc = new JFileChooser();
		btnBrowse.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				int returnVal = fc.showOpenDialog(frmSimplex);
				if (returnVal == JFileChooser.APPROVE_OPTION) {
					txtPath.setText(fc.getSelectedFile().getAbsolutePath());
				}
			}
		});
		panel_11.add(btnBrowse);
		
		rdbtnF4 = new JRadioButton("f4(x,y) = | (x-y) * (x+y) | + (x^2+y^2)^0.5");
		GridBagConstraints gbc_rdbtnF4 = new GridBagConstraints();
		gbc_rdbtnF4.anchor = GridBagConstraints.WEST;
		gbc_rdbtnF4.gridx = 0;
		gbc_rdbtnF4.gridy = 4;
		panel.add(rdbtnF4, gbc_rdbtnF4);
		
		buttonGroup.add(rdbtnF1);
		buttonGroup.add(rdbtnF2);
		buttonGroup.add(rdbtnF3);
		buttonGroup.add(rdbtnF4);
		
		JPanel panel_1 = new JPanel();
		frmSimplex.getContentPane().add(panel_1, BorderLayout.CENTER);
		GridBagLayout gbl_panel_1 = new GridBagLayout();
		gbl_panel_1.columnWidths = new int[]{0, 0};
		gbl_panel_1.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0};
		gbl_panel_1.columnWeights = new double[]{1.0, Double.MIN_VALUE};
		gbl_panel_1.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE};
		panel_1.setLayout(gbl_panel_1);
		
		JPanel panel_2 = new JPanel();
		GridBagConstraints gbc_panel_2 = new GridBagConstraints();
		gbc_panel_2.insets = new Insets(0, 0, 5, 0);
		gbc_panel_2.fill = GridBagConstraints.BOTH;
		gbc_panel_2.gridx = 0;
		gbc_panel_2.gridy = 0;
		panel_1.add(panel_2, gbc_panel_2);
		
		JLabel lblA = new JLabel("a:");
		panel_2.add(lblA);
		
		txtA = new JTextField();
		txtA.setText("1");
		panel_2.add(txtA);
		txtA.setColumns(10);
		
		JPanel panel_3 = new JPanel();
		GridBagConstraints gbc_panel_3 = new GridBagConstraints();
		gbc_panel_3.insets = new Insets(0, 0, 5, 0);
		gbc_panel_3.fill = GridBagConstraints.BOTH;
		gbc_panel_3.gridx = 0;
		gbc_panel_3.gridy = 1;
		panel_1.add(panel_3, gbc_panel_3);
		
		JLabel lblB = new JLabel("b:");
		panel_3.add(lblB);
		
		txtB = new JTextField();
		txtB.setText("0.5");
		txtB.setColumns(10);
		panel_3.add(txtB);
		
		JPanel panel_4 = new JPanel();
		GridBagConstraints gbc_panel_4 = new GridBagConstraints();
		gbc_panel_4.fill = GridBagConstraints.BOTH;
		gbc_panel_4.insets = new Insets(0, 0, 5, 0);
		gbc_panel_4.gridx = 0;
		gbc_panel_4.gridy = 2;
		panel_1.add(panel_4, gbc_panel_4);
		
		JLabel lblC = new JLabel("c:");
		panel_4.add(lblC);
		
		txtC = new JTextField();
		txtC.setText("2");
		txtC.setColumns(10);
		panel_4.add(txtC);
		
		JPanel panel_5 = new JPanel();
		GridBagConstraints gbc_panel_5 = new GridBagConstraints();
		gbc_panel_5.insets = new Insets(0, 0, 5, 0);
		gbc_panel_5.fill = GridBagConstraints.BOTH;
		gbc_panel_5.gridx = 0;
		gbc_panel_5.gridy = 3;
		panel_1.add(panel_5, gbc_panel_5);
		
		JLabel lblE = new JLabel("e:");
		panel_5.add(lblE);
		
		txtE = new JTextField();
		txtE.setHorizontalAlignment(SwingConstants.LEFT);
		txtE.setText("0.000000001");
		txtE.setColumns(10);
		panel_5.add(txtE);
		
		JPanel panel_6 = new JPanel();
		GridBagConstraints gbc_panel_6 = new GridBagConstraints();
		gbc_panel_6.insets = new Insets(0, 0, 5, 0);
		gbc_panel_6.fill = GridBagConstraints.BOTH;
		gbc_panel_6.gridx = 0;
		gbc_panel_6.gridy = 4;
		panel_1.add(panel_6, gbc_panel_6);
		
		JLabel lblX = new JLabel("x0:");
		panel_6.add(lblX);
		
		txtX = new JTextField();
		txtX.setText("0,0");
		txtX.setColumns(10);
		panel_6.add(txtX);
		
		JPanel panel_7 = new JPanel();
		GridBagConstraints gbc_panel_7 = new GridBagConstraints();
		gbc_panel_7.fill = GridBagConstraints.BOTH;
		gbc_panel_7.gridx = 0;
		gbc_panel_7.gridy = 5;
		panel_1.add(panel_7, gbc_panel_7);
		
		JLabel lblT = new JLabel("t:");
		panel_7.add(lblT);
		
		txtT = new JTextField();
		txtT.setText("1");
		txtT.setColumns(10);
		panel_7.add(txtT);
		
		JPanel panel_8 = new JPanel();
		frmSimplex.getContentPane().add(panel_8, BorderLayout.EAST);
		GridBagLayout gbl_panel_8 = new GridBagLayout();
		gbl_panel_8.columnWidths = new int[]{0, 0};
		gbl_panel_8.rowHeights = new int[]{0, 0, 0, 0, 0, 0};
		gbl_panel_8.columnWeights = new double[]{1.0, Double.MIN_VALUE};
		gbl_panel_8.rowWeights = new double[]{1.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE};
		panel_8.setLayout(gbl_panel_8);
		
		JButton btnCalculate = new JButton("Calculate");
		btnCalculate.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				error = false;
				getXi();
				if(!error)
					calculate();
			}
		});
		GridBagConstraints gbc_btnCalculate = new GridBagConstraints();
		gbc_btnCalculate.insets = new Insets(0, 0, 5, 0);
		gbc_btnCalculate.gridx = 0;
		gbc_btnCalculate.gridy = 0;
		panel_8.add(btnCalculate, gbc_btnCalculate);
		
		JPanel panel_10 = new JPanel();
		GridBagConstraints gbc_panel_10 = new GridBagConstraints();
		gbc_panel_10.insets = new Insets(0, 0, 5, 0);
		gbc_panel_10.fill = GridBagConstraints.BOTH;
		gbc_panel_10.gridx = 0;
		gbc_panel_10.gridy = 1;
		panel_8.add(panel_10, gbc_panel_10);
		
		JPanel panel_9 = new JPanel();
		frmSimplex.getContentPane().add(panel_9, BorderLayout.SOUTH);
		
		JLabel lblSolution = new JLabel("Solution:");
		panel_9.add(lblSolution);
		
		panel_9.add(lblXsol);
	}

	protected double[] readFile() throws IOException {
		BufferedReader reader = new BufferedReader(new InputStreamReader(new BufferedInputStream(new FileInputStream(txtPath.getText()))));
		String line = reader.readLine();
		double[] p = new double[n];
		int i = 0;
		for(String s : line.split(","))
			p[i++] = Double.parseDouble(s);
		return p;
	}

	private void calculate(){
		int h,l;
		double[] f = new double[n+1];
		double[] xc = new double[n];
		double[] xr = new double[n];
		double[] xe = new double[n];	
		double[] xk = new double[n];
		
		
		
		double e = Double.parseDouble(txtE.getText());
		double fxr;
		do{
			f = calculateFs();
			h = findMax(f);
			l = findMin(f);
			xc = calcXc(h);
			
			xr = reflect(xc,h);
			fxr = calculateF(xr);
			
			if(fxr < f[l]){
				xe = expand(xc, xr);
				if(calculateF(xe) < f[l])
					x[h] = xe;
				else
					x[h] = xr;
			}
			
			else{
				if(checkXr(fxr,f,h)){
					if(fxr < f[h])
						x[h] = xr;
					
					xk = contract(xc, h);
					
					if(calculateF(xk) < f[h])
						x[h] = xk;
					else
						getCloser(l);
				}
				else
					x[h] = xr;
			}
			//print(f, h, l, xc, xr, xk,xe);
		}while(stop(xc) > e);
		StringBuffer sb = new StringBuffer();
		for(int i=0;i<n;i++)
			sb.append(Math.round(x[h][i])+",");
		sb.deleteCharAt(sb.length()-1);
		lblXsol.setText("X= ("+sb.toString()+")");
		System.out.println("rez je= "+x[h][0]+", "+x[h][1]);
	}
	
	public double[] reflect(double[] xc,int h){
		double[] xr = new double[n];
		double a = Double.parseDouble(txtA.getText());
		for(int i = 0;i<n;i++)
			xr[i] = (1+a)*xc[i] - a*x[h][i];
		return xr;
	}
	public double[] expand(double[] xc, double[] xr){
		double[] xe = new double[n];
		double c = Double.parseDouble(txtC.getText());
		for(int i = 0;i<n;i++)
			xe[i] = (1-c)*xc[i] + c*xr[i];
		return xe;
	}
	
	public double[] contract(double[] xc,int h){
		double[] xk = new double[n];
		double b = Double.parseDouble(txtB.getText());
		for(int i = 0;i<n;i++)
			xk[i] = (1-b)*xc[i] + b*x[h][i];
		return xk;
	}
	public double[] calcXc(int h){
		double[] xc = new double[n];
		for(int i = 0;i<n+1;i++)
			for(int j = 0; j < n; j++)
				if(i != h)
					xc[j] += x[i][j];
		for(int j = 0; j < n; j++)
			xc[j]/=n;
		return xc;
	}
	
	public void getCloser(int l){
		for(int i = 0; i< n+1; i++)
			for(int j = 0;j<n;j++)
			if(i != l)
				x[i][j] = 0.5*(x[l][j] + x[i][j]);
	}
	
	public double stop(double[] xc){
		double sum = 0;
		double fxc = calculateF(xc);
		for(int i = 0; i<n+1;i++)
			sum += Math.pow((calculateF(x[i])-fxc), 2);
		return Math.sqrt(sum/n);
	}
	public boolean checkXr(double fxr, double[] f,int h){
		for(int i = 0;i<f.length;i++)
			if(i != h)
				if(fxr < f[i])
					return false;
		return true;
	}
	
	private void print(double[] f, int h, int l, double[] xc, double[] xr, double[] xk, double[] xe){
		for(int i = 0; i < n+1; i++)
			System.out.println(i+": "+x[i][0]+", "+x[i][1]);
		System.out.print("f: ");
		for(int i = 0;i<n+1;i++)
			System.out.print(f[i]+" ");
		System.out.println("\nh: "+h);
		System.out.println("l: "+l);
		System.out.print("xc: ");
		for(int i = 0;i<n;i++)
			System.out.print(xc[i]+" ");
		System.out.println("\nf(xc): "+calculateF(xc));
		System.out.print("xr: ");
		for(int i = 0;i<n;i++)
			System.out.print(xr[i]+" ");
		System.out.println("\nf(xr): "+calculateF(xr));
		System.out.print("xe: ");
		for(int i = 0;i<n;i++)
			System.out.print(xe[i]+" ");
		System.out.println("\nf(xe): "+calculateF(xe));
		System.out.print("xk: ");
		for(int i = 0;i<n;i++)
			System.out.print(xk[i]+" ");
		System.out.println("\nf(xk): "+calculateF(xk));
	}
	
	private double[] calculateFs(){
		double[] fs = new double[n+1];
		if(f == 1)
			for(int i = 0;i<n+1;i++)
				fs[i] = f1(x[i][0], x[i][1]);
		else if(f == 2)
			for(int i = 0;i<n+1;i++)
				fs[i] = f2(x[i][0], x[i][1]);
		else if(f == 3)
			for(int i = 0;i<n+1;i++)
				fs[i] = f3(x[i]);
		else if(f == 4)
			for(int i = 0;i<n+1;i++)
				fs[i] = f4(x[i][0], x[i][1]);
		return fs;
	}
	
	private double calculateF(double[] x){
		if(f == 1)
			return f1(x[0],x[1]);
		else if(f==2)
			return f2(x[0],x[1]);
		else if(f==3)
			return f3(x);
		else if(f==4)
			return f2(x[0],x[1]);
		return 0;
		
	}
	private int findMax(double[] f){
		double max = Double.MIN_VALUE;
		int index = 0;
		for(int i = 0;i<f.length;i++)
			if(f[i] > max){
				max = f[i];
				index = i;
			}
		return index;
	}
	
	private int findMin(double[] f){
		double min = Double.MAX_VALUE;
		int index = 0;
		for(int i = 0;i<f.length;i++)
			if(f[i] < min){
				min = f[i];
				index = i;
			}
		return index;
	}
	
	private void whatFunction(){
		n = 2;
		if(rdbtnF1.isSelected())
			f = 1;
		else if(rdbtnF2.isSelected())
			f = 2;
		else if(rdbtnF3.isSelected()){
			f = 3;
			n = 5;
			try {
				p = readFile();
			} catch (IOException e) {
				e.printStackTrace();
			}	
		}
		else if(rdbtnF4.isSelected())
			f = 4;
	}
	
	private void getXi() {
		whatFunction();
		x = new double[n+1][n];
		double t = Double.parseDouble(txtT.getText());
		x[0] = getX0();
		if(!error){
			double[][] d = new double[n][n];
			double a1 = (t/(n*Math.sqrt(2))) * (Math.sqrt(n+1) + n - 1);
			double a2 = (t/(n*Math.sqrt(2))) * (Math.sqrt(n+1) - 1);
			for(int i = 0; i < n; i++)
				for(int j = 0; j < n; j++)
					if(i != j)
						d[i][j] = a2;
					else
						d[i][j] = a1;
			for(int i = 0; i < n; i++)
				for(int j = 0; j < n; j++)
					x[i+1][j] = x[0][j] + d[i][j];
		}
	}

	private double[] getX0(){
		String[] s = txtX.getText().split(",");
		if(s.length != n){
			JOptionPane.showMessageDialog(frmSimplex, "Wrong dimension of x0", "Error", JOptionPane.ERROR_MESSAGE);
			error = true;
			return null;
		}
		double[] x0 = new double[n];
		for(int i = 0; i < n; i++)
			x0[i] = Double.parseDouble(s[i]);
		return x0;
	}
	
	private double f1(double x,double y){
		return 10*(Math.pow(Math.pow(x, 2)-y,2)) + Math.pow(1-x, 2);
	}
	
	private double f2(double x,double y){
		return Math.pow(x-4, 2) + 4*Math.pow(y-2, 2);
	}
	
	private double f3(double[] x){
		double rez = 0;
		for(int i=0;i<5;i++)
			rez += Math.pow(x[i]-p[i], 2);
		return rez;
	}
	
	private double f4(double x, double y){
		return Math.abs((x-y)*(x+y)) + Math.pow(Math.pow(x, 2)+Math.pow(y, 2), 0.5);
	}
}
